<script setup>
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'

const props = defineProps({
  modelValue: {
    type: [String, Number, Object],
    default: '',
  },
  options: {
    type: Array,
    default: () => [],
    required: true,
  },
  placeholder: {
    type: String,
    default: '请选择',
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  clearable: {
    type: Boolean,
    default: false,
  },
  valueKey: {
    type: String,
    default: 'value',
  },
  labelKey: {
    type: String,
    default: 'label',
  },
})

const emit = defineEmits(['update:modelValue', 'change'])

const isOpen = ref(false)
const selectedOption = ref(null)
const selectRef = ref(null)

// 计算当前选中项的标签文本
const selectedLabel = computed(() => {
  if (!selectedOption.value) return ''
  return typeof selectedOption.value === 'object'
    ? selectedOption.value[props.labelKey]
    : selectedOption.value
})

// 根据value查找选项
const findOptionByValue = (value) => {
  if (!value) return null

  return props.options.find((option) => {
    const optionValue =
      typeof option === 'object' ? option[props.valueKey] : option
    return optionValue === value
  })
}

// 初始化选中项
watch(
  () => props.modelValue,
  (newValue) => {
    selectedOption.value = findOptionByValue(newValue)
  },
  { immediate: true }
)

// 处理选择
const handleSelect = (option) => {
  const value = typeof option === 'object' ? option[props.valueKey] : option
  selectedOption.value = option
  emit('update:modelValue', value)
  emit('change', value)
  isOpen.value = false
}

// 清除选择
const clearSelection = (event) => {
  event.stopPropagation()
  selectedOption.value = null
  emit('update:modelValue', '')
  emit('change', '')
}

// 切换下拉菜单显示状态
const toggleDropdown = () => {
  if (props.disabled) return
  isOpen.value = !isOpen.value
}

// 点击外部关闭下拉菜单
const handleClickOutside = (event) => {
  if (selectRef.value && !selectRef.value.contains(event.target)) {
    isOpen.value = false
  }
}

// 生命周期钩子
onMounted(() => {
  document.addEventListener('click', handleClickOutside)
})

onBeforeUnmount(() => {
  document.removeEventListener('click', handleClickOutside)
})
</script>

<template>
  <div
    class="custom-select"
    ref="selectRef"
    :class="{ 'is-disabled': disabled, 'is-active': isOpen }"
  >
    <div class="select-trigger" @click="toggleDropdown">
      <span class="select-value" :class="{ 'is-placeholder': !selectedLabel }">
        {{ selectedLabel || placeholder }}
      </span>
      <div class="select-icons">
        <span
          v-if="clearable && selectedLabel"
          class="select-clear-icon"
          @click="clearSelection"
        >
          ✕
        </span>
        <span class="select-arrow-icon" :class="{ 'is-reverse': isOpen }"
          >▼</span
        >
      </div>
    </div>

    <div class="select-dropdown" v-show="isOpen">
      <ul class="select-options">
        <li
          v-for="(option, index) in options"
          :key="index"
          class="select-option"
          :class="{
            'is-selected':
              selectedOption === option ||
              (typeof option === 'object' &&
                typeof selectedOption === 'object' &&
                option[valueKey] === selectedOption[valueKey]),
          }"
          @click="handleSelect(option)"
        >
          {{ typeof option === 'object' ? option[labelKey] : option }}
        </li>
      </ul>
    </div>
  </div>
</template>

<style scoped>
.custom-select {
  position: relative;
  width: 100%;
  font-size: 14px;
  color: #606266;
}

.select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 40px;
  padding: 0 15px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  background-color: #fff;
  cursor: pointer;
  transition: all 0.2s;
}

.is-active .select-trigger {
  border-color: #409eff;
}

.select-value {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.is-placeholder {
  color: #c0c4cc;
}

.select-icons {
  display: flex;
  align-items: center;
}

.select-clear-icon {
  margin-right: 8px;
  font-size: 12px;
  color: #c0c4cc;
}

.select-clear-icon:hover {
  color: #909399;
}

.select-arrow-icon {
  font-size: 12px;
  transition: transform 0.3s;
  color: #c0c4cc;
}

.select-arrow-icon.is-reverse {
  transform: rotate(180deg);
}

.select-dropdown {
  position: absolute;
  top: calc(100% + 5px);
  left: 0;
  width: 100%;
  max-height: 200px;
  overflow-y: auto;
  background-color: #fff;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 10;
}

.select-options {
  margin: 0;
  padding: 0;
  list-style: none;
}

.select-option {
  padding: 8px 15px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.select-option:hover {
  background-color: #f5f7fa;
}

.select-option.is-selected {
  color: #409eff;
  font-weight: bold;
  background-color: #f0f9ff;
}

.is-disabled {
  cursor: not-allowed;
}

.is-disabled .select-trigger {
  background-color: #f5f7fa;
  color: #c0c4cc;
  cursor: not-allowed;
}
</style>
